package com.ruoyi.web.service.devicedata.impl;

import com.ruoyi.web.domain.warning.FactorInfo;
import com.ruoyi.web.enums.AggreEnum;
import com.ruoyi.web.middleware.influxdb.Influxdb2Service;
import com.ruoyi.web.pojo.dto.devicedata.*;
import com.ruoyi.web.pojo.request.devicedata.DeviceRainCountRequest;
import com.ruoyi.web.pojo.vo.devicedata.PropertyDataVO;
import com.ruoyi.web.service.device.DeviceInfoService;
import com.ruoyi.web.service.devicedata.DevicePropertyService;
import com.ruoyi.web.service.warning.FactorInfoService;
import com.ruoyi.web.utils.influxdb.DeviceAggreDataParam;
import com.ruoyi.web.utils.influxdb.DeviceData;
import com.ruoyi.web.utils.v2.V2RremoteCall;
import com.ruoyi.web.utils.v2.property.V2DeviceProperty;
import com.ruoyi.web.utils.wuqing.WQRremoteCall;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @desc  设备数据查询
 * @author fwx 2024/2/26 16:38
 **/
@Service
public class DevicePropertyServiceImpl implements DevicePropertyService {

    @Autowired
    private FactorInfoService factorInfoService;

    @Autowired
    private Influxdb2Service influxdb2Service;

    @Autowired
    private DeviceInfoService deviceInfoService;


    @Override
    public List<V2DeviceProperty> latest(String deviceId, String startTime, String endTime){
        List<V2DeviceProperty> latest = V2RremoteCall.latest(deviceId, startTime, endTime);

        Map<String, FactorInfo> factorMap = factorInfoService.getAllMap();

        for (V2DeviceProperty property : latest) {
            String factorKey = property.conExpandsStr("standardId");
            property.setFactorInfo(factorMap.get(factorKey));
        }
        
        return latest;
    }


    @Override
    public PropertyDataVO countPropertyData(String deviceId, String factorName){
        return  WQRremoteCall.countPropertyData(deviceId,factorName);
    }

    @Override
    public List<DeviceFactorCountData> countRainData(DeviceRainCountRequest request){
       return WQRremoteCall.countRainData(request);
    }

    //环境因子统计 - 小时平均
    public PropertyAirCount getPropertyAirCount(DeviceAggreDataParam dataParam){
        PropertyAirCount airCount = new PropertyAirCount();
        DeviceAggreDataParam param = dataParam.getHour();
        param.setType(AggreEnum.AVG);
        DeviceData data = influxdb2Service.getMaxMonitorData(param);
        airCount.setHourAvg(data.getValue());
        return airCount;
    }

    public PropertyHumCount getPropertyHumCount(DeviceAggreDataParam param){
        PropertyHumCount count = new PropertyHumCount();

        //年干旱天数
        DeviceAggreDataParam yearWinParam = param.buildYear();
        yearWinParam.setType(AggreEnum.AVG);
        List<DeviceData> yearWinSum = influxdb2Service.aggregateWindow(yearWinParam);
        long yearDuration = yearWinSum.stream().filter(data ->  data.getValue() != null && data.getValue() < 50)
                .count();
        count.setDroughtYearDuration(yearDuration);

        //月干旱天数
        DeviceAggreDataParam monthWinParam = param.getMonth();
        monthWinParam.setType(AggreEnum.AVG);
        List<DeviceData> monthWinSum = influxdb2Service.aggregateWindow(monthWinParam);

        long monthDuration = monthWinSum.stream().filter(data ->  data.getValue() != null && data.getValue() < 50)
                .count();

        count.setDroughtMonthDuration(monthDuration);


        return count;
    }

    public PropertyWindCount getPropertyWindCount(DeviceAggreDataParam param){
        PropertyWindCount windCount = new PropertyWindCount();

        List<DeviceData> yearHistory = influxdb2Service.getFactorHistoryData(param);

        for (DeviceData deviceData : yearHistory) {
            windCount.countRate(deviceData.getValue());
        }

        return windCount;
    }

    /**
     * @desc  得到降雨量统计数据
     * @author fwx 2024/2/29 17:15
     **/
    public PropertyRainCount getPropertyRainCount(DeviceAggreDataParam param){
        PropertyRainCount count = new PropertyRainCount();

        //年累计降雨天数
        DeviceAggreDataParam yearWinParam = param.buildYear();
        yearWinParam.setType(AggreEnum.SUM);
        List<DeviceData> yearWinSum = influxdb2Service.aggregateWindow(yearWinParam);

        long yearDuration = yearWinSum.stream().filter(data ->  data.getValue() != null && data.getValue() > 0)
                .count();
        count.setYearRainDuration(yearDuration);

        //降雨量持续天数
        DeviceAggreDataParam allWinParam = param.buildAll();
        allWinParam.setType(AggreEnum.SUM);
        List<DeviceData> allWinSum = influxdb2Service.aggregateWindow(allWinParam);

        long allDuration = allWinSum.stream().filter(data ->  data.getValue() != null && data.getValue() > 0)
                .count();

        count.setSumRainDuration(allDuration);

        //本月降雨量持续天数
        DeviceAggreDataParam monthWinParam = param.getMonth();
        monthWinParam.setType(AggreEnum.SUM);

        List<DeviceData> monthWinSum = influxdb2Service.aggregateWindow(monthWinParam);

        long monthDuration = monthWinSum.stream().filter(data ->  data.getValue() != null && data.getValue() > 0)
                .count();

        count.setMonthRainDuration(monthDuration);

        //今日累计降雨
        DeviceAggreDataParam dayWinParam = param.getDay();

        dayWinParam.setType(AggreEnum.SUM);
        DeviceData dayWinSum = influxdb2Service.getMaxMonitorData(dayWinParam);

        count.setDayRain(dayWinSum.getValue());

        return count;
    }

    /**
     * @desc  得到温度统计数据
     * @author fwx 2024/2/29 16:40
     **/
    public PropertyTempCount getPropertyTempCount(DeviceAggreDataParam param){

        DeviceAggreDataParam yearWinParam = param.buildYear();
        yearWinParam.setType(AggreEnum.AVG);
        List<DeviceData> yearWinSvg = influxdb2Service.aggregateWindow(yearWinParam);

        //活动积温
        double sum = yearWinSvg.stream().filter(data ->  data.getValue() != null && data.getValue() > 10).mapToDouble(DeviceData::getValue).sum();
        PropertyTempCount tempCount = new PropertyTempCount();
        tempCount.setAccumulated(sum);

        //有效积温
        double effSum = yearWinSvg.stream().filter(data ->  data.getValue() != null && data.getValue() > 10)
                .mapToDouble(data -> data.getValue() - 10)
                .sum();
        tempCount.setAccumulated(sum);
        tempCount.setEffective(effSum);

        //高温持续天数
        yearWinParam.setType(AggreEnum.MAX);
        List<DeviceData> yearWinMax = influxdb2Service.aggregateWindow(yearWinParam);
        long highDurtion = yearWinMax.stream().filter(data ->  data.getValue() != null && data.getValue() > 35)
                .count();

        //霜冻持续天数
        yearWinParam.setType(AggreEnum.MIN);
        List<DeviceData> yearWinMin = influxdb2Service.aggregateWindow(yearWinParam);
        long lowDurtion = yearWinMin.stream().filter(data ->  data.getValue() != null && data.getValue() < 0)
                .count();

        tempCount.setHighDuration(highDurtion);
        tempCount.setFrostDuration(lowDurtion);

        return tempCount;
    }

    /**
     * @desc  封装最大,最小,平均值
     * @author fwx 2024/2/28 15:47
     **/
    public PropertyNumCount setNumCountValue(DeviceAggreDataParam yearParam){
        Map<String, DeviceData> yearDataMap = this.getNumCount(yearParam);
        PropertyNumCount count = new PropertyNumCount();
        count.setMax(yearDataMap.get(AggreEnum.MAX.getName()).getValue());
        count.setMin(yearDataMap.get(AggreEnum.MIN.getName()).getValue());
        count.setMaxTime(yearDataMap.get(AggreEnum.MAX.getName()).getDataTime());
        count.setMinTime(yearDataMap.get(AggreEnum.MIN.getName()).getDataTime());
        count.setAvg(yearDataMap.get(AggreEnum.AVG.getName()).getValue());
        return count;
    }

    /**
     * @desc  得到常年的统计数据
     * @author fwx 2024/3/5 15:27
     **/
    public PropertyNumCount getPreviousCountValue(List<DeviceAggreDataParam> beforeYear){
        PropertyNumCount count = new PropertyNumCount();

        List<Double> maxList = new ArrayList<>();
        List<Double> minList = new ArrayList<>();
        List<Double> avgList = new ArrayList<>();

        for (DeviceAggreDataParam param : beforeYear) {
            Map<String, DeviceData> numCount = this.getNumCount(param);

            Double maxValue = numCount.get(AggreEnum.MAX.getName()).getValue();

            if(maxValue != null && !Objects.equals(maxValue,0d)){
                maxList.add(maxValue);
            }

            Double minValue = numCount.get(AggreEnum.MIN.getName()).getValue();

            if(minValue != null && !Objects.equals(minValue,0d)){
                minList.add(minValue);
            }

            Double avgValue = numCount.get(AggreEnum.AVG.getName()).getValue();

            if(avgValue != null && !Objects.equals(avgValue,0d)){
                avgList.add(avgValue);
            }
        }

        //常年平均
        if(avgList.size() > 0){
            count.setBeforeAvg(avgList.stream().mapToDouble(Double::valueOf).sum() / avgList.size());
        }

        //常年最大
        if(maxList.size() > 0){
            count.setBeforeMax(maxList.stream().mapToDouble(Double::valueOf).sum() / maxList.size());
        }

        //常年最小
        if(minList.size() > 0){
            count.setBeforeMin(minList.stream().mapToDouble(Double::valueOf).sum() / minList.size());
        }

        return count;
    }



    /**
     * @desc  根据参数查询指定时间的最大,最小,平均值
     * @author fwx 2024/2/28 15:47
     **/
    public Map<String,DeviceData> getNumCount(DeviceAggreDataParam param){

        Map<String,DeviceData> resultMap = new HashMap<>();

        param.setType(AggreEnum.MAX);
        DeviceData max = influxdb2Service.getMaxMonitorData(param);

        param.setType(AggreEnum.MIN);
        DeviceData min = influxdb2Service.getMaxMonitorData(param);

        param.setType(AggreEnum.AVG);
        DeviceData avg = influxdb2Service.getMaxMonitorData(param);

        resultMap.put(AggreEnum.MAX.getName(),max);
        resultMap.put(AggreEnum.MIN.getName(),min);
        resultMap.put(AggreEnum.AVG.getName(),avg);

        return resultMap;
    }

}
